// -----------------------------
// Author: 		Dhaenens Gert	
// Creation: 	8/2/2013 6:59:07 PM				
// -----------------------------

#include <tchar.h>
#include <iostream>

#include "ObjectLua.h"

#ifdef _DEBUG
#	include <crtdbg.h>
#	define ENABLE_LEAKCHECK		_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#	define LEAKCHECK(x)			_CrtSetBreakAlloc(x)
#else
#	define ENABLE_LEAKCHECK		
#	define LEAKCHECK(x)			
#endif

#ifdef _WIN32
#	define WIN32_LEAN_AND_MEAN
#	include <Windows.h>
#endif

#include "Image.h"

#include <sstream>
#include <time.h>
#include <stdlib.h>
#include <direct.h>

std::string log_timestamp()
{
	time_t t;
	time(&t);
	tm timeStruct = {};
	localtime_s(&timeStruct,&t);
	std::stringstream stream;
	stream << "[";
	stream << (((int) timeStruct.tm_hour < 10)?("0"):(""));
	stream << timeStruct.tm_hour;
	stream << ":";
	stream << (((int) timeStruct.tm_min < 10)?("0"):(""));
	stream << timeStruct.tm_min;
	stream << ":";
	stream << (((int) timeStruct.tm_sec < 10)?("0"):(""));
	stream << timeStruct.tm_sec;
	stream << "]";
	return stream.str().c_str();
}
void log_write(const char* lpMsg)
{
	if(!lpMsg)
		return;

	std::stringstream stream;
	std::string timeStamp = log_timestamp();
	stream << timeStamp << "\t" << lpMsg << "\n";
	std::cout << stream.str();
}

void verifyValues(int* lpVals, int valCount)
{
	for (int i = 0; i < valCount; ++i)
	{
		std::stringstream stream;
		stream << "i:\t" << lpVals[i];
		log_write(stream.str().c_str());
	}
}

std::string GetWorkPath()
{
	size_t maxLen = MAX_PATH;
	char* lpPath = new char[maxLen];
	_getcwd(lpPath, maxLen);

	std::string str = std::string(lpPath);
	delete[] lpPath;
	return str;
}

void RegisterFunctions(ObjectLua::Lua& lua)
{
	// Register Function
	ObjectLua::LuaTable logTable = lua.getGlobals()->addTable("Log");
	logTable.addFunction("write", &log_write);
	logTable.addFunction("verifyValues", &verifyValues);
}
void RegisterObject(ObjectLua::Lua& lua)
{
	// Register the Object Class
	ObjectLua::LuaClass<Object> objectClass = lua.getGlobals()->addClass<Object>("Object");
	objectClass.addMethod("setName", &Object::setName);
	objectClass.addMethod("getName", &Object::getName);
	objectClass.addDatamember("Value", &Object::Value);
}
void RegisterImage(ObjectLua::Lua& lua)
{
	// Try to register the Image class
	ObjectLua::LuaClass<Image> imageClass = lua.getGlobals()->addClass<Image>("Image");
	imageClass.inheritFrom<Object>();
	imageClass.addConstructor<const char*>();
	imageClass.addProxyConstructor<const char*, int, int>("Create");
	imageClass.addDestructor();

	imageClass.addMethod("setWidth", &Image::setWidth);
	imageClass.addMethod("setHeight", &Image::setHeight);
	imageClass.addMethod("getWidth", &Image::getWidth);
	imageClass.addMethod("getHeight", &Image::getHeight);

	imageClass.addDatamember("Width", &Image::m_Width);
	imageClass.addDatamember("Height", &Image::m_Height);

	imageClass.addStaticDatamember("MaxWidth", &Image::MaxWidth, true);
	imageClass.addStaticDatamember("MaxHeight", &Image::MaxHeight, true);

	imageClass.addUnaryMinusOperator<Image>();
	imageClass.addAdditionOperator<Image, Image>();
	imageClass.addSubtractionOperator<Image, Image>();
	imageClass.addMultiplicationOperator<Image, float>();
	imageClass.addDivisionOperator<Image, float>();
}

void TestImage(ObjectLua::Lua& lua)
{
	Image* lpImage = new Image("GlobalImage", 600, 100);
	lua.getGlobals()->addObject("GlobalImage", "Image", lpImage);

	// Load the Script
	ObjectLua::LuaScript script(&lua, "Scripts//main.lua");
	script.load();
	script.run();

	ObjectLua::LuaVariable var = script.getVariable("g_GlobalVar");
	log_write(var.get<const char*>());

	script.callFunction<Image*>("InspectImage", lpImage);

	script.reload();

	delete lpImage;
}

int _tmain(int argc, TCHAR* lpArgs[])
{
	ENABLE_LEAKCHECK;
	//LEAKCHECK(1651);

	// Set the Error Policy
	ObjectLua::LuaError::setPolicy(ObjectLua::ErrorPolicy::Default);
	// Create the Lua
	ObjectLua::Lua lua;

	// Add the Working Directory to the Package Path
	std::string workPath = GetWorkPath();
	lua.addPath(workPath.c_str());

	try
	{
		RegisterFunctions(lua);
		RegisterObject(lua);
		RegisterImage(lua);
		TestImage(lua);
	}
	catch(ObjectLua::LuaException& e)
	{
		std::cout << "Unhandled Lua Exception\n";
		std::cout << e.message() << "\n";
	}

	std::cout << "\nPress Enter to exit...\n";
	std::cin.get();
	return 0;
}